﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Domain.Core;
using Domain.MainModule.Entities;
using Domain.Core.Specification;
using Domain.MainModule.BankAccounts;
using Domain.MainModule.BankAccountTypes;
using Domain.MainModule.Banks;

namespace Application.MainModule.BankAccountsManagement
{
    public class BankAccountManagementService : IBankAccountManagementService, IDisposable
    {
        #region members

        IBankAccountRepository _BankAccountRepository;
        IBankAccountTypeRepository _BankAccountTypeRepository;
        IBankRepository _BankRepository;

        #endregion

        #region constructor

        public BankAccountManagementService(IBankAccountRepository bankAccountRepository, IBankAccountTypeRepository bankAccountTypeRepository, IBankRepository bankRepository)
        {
            if (bankAccountRepository == (IBankAccountRepository)null)
            {
                throw new ArgumentNullException(Resources.Messages.exception_DependenciesAreNotInitialized);
            }

            _BankAccountRepository = bankAccountRepository;
            
            if (bankAccountTypeRepository == (IBankAccountTypeRepository)null)
            {
                throw new ArgumentNullException(Resources.Messages.exception_DependenciesAreNotInitialized);
            }

            _BankAccountTypeRepository = bankAccountTypeRepository;

            if (bankRepository == (IBankRepository)null)
            {
                throw new ArgumentNullException(Resources.Messages.exception_DependenciesAreNotInitialized);
            }

            _BankRepository = bankRepository;
        }

        #endregion

        #region public methods

        public void AddBankAccount(BankAccount bankAccount)
        {
            IUnitOfWork unitOfWork = _BankAccountRepository.UnitOfWork as IUnitOfWork;
            _BankAccountRepository.Add(bankAccount);
            unitOfWork.Commit();
        }

        public void ChangeBankAccount(BankAccount bankAccount)
        {
            IUnitOfWork unitOfWork = _BankAccountRepository.UnitOfWork as IUnitOfWork;
            _BankAccountRepository.Modify(bankAccount);
            unitOfWork.CommitAndRefreshChanges();
        }

        public void RemoveBankAccount(BankAccount bankAccount)
        {
            if (bankAccount == (BankAccount)null)
                throw new ArgumentNullException("bankAccount");

            IUnitOfWork unitOfWork = _BankAccountRepository.UnitOfWork as IUnitOfWork;
            bankAccount.IsEnabled = false;
            _BankAccountRepository.Modify(bankAccount);
            unitOfWork.CommitAndRefreshChanges();
        }

        public List<BankAccount> FindBankAccountsByUserId(Guid userId)
        {
            BankAccountUserIdSpecification spec = new BankAccountUserIdSpecification(userId);
            return _BankAccountRepository.FindBankAccounts(spec).ToList<BankAccount>();
        }

        public List<BankAccount> FindPagedBankAccounts(int pageIndex, int pageCount)
        {
            if (pageIndex < 0)
                throw new ArgumentException(Resources.Messages.exception_InvalidPageIndex, "pageIndex");

            if (pageCount <= 0)
                throw new ArgumentException(Resources.Messages.exception_InvalidPageCount, "pageCount");

            bool enabled = true;
            Specification<BankAccount> onlyEnabledSpec = new DirectSpecification<BankAccount>(c => c.IsEnabled == enabled);

            return _BankAccountRepository.GetPagedElements(pageIndex, pageCount, c => c.BankAccountNumber, onlyEnabledSpec, true).ToList();

        }

        public List<BankAccountType> GetAllBankAccountTypes()
        {
            return this._BankAccountTypeRepository.GetAll().ToList();
        }

        public List<Bank> GetAllBanks()
        {
            return this._BankRepository.GetAll().ToList();
        }

        #endregion

        #region IDisposable

        /// <summary>
        /// Dispose associated context with this domain service
        /// </summary>
        public void Dispose()
        {
            if (_BankAccountRepository != null
                &&
                _BankAccountRepository.UnitOfWork != null)
            {
                _BankAccountRepository.UnitOfWork.Dispose();
            }
        }

        #endregion
    }
}
